﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace Kompetition
{
    class Competition
    {
        Dictionary<string, int> teams = new Dictionary<string, int>();
        List<Category> categories = new List<Category>();
        int currentTeam = 0;
        int unansweredQ = 0;

        public Competition(string filepath)
        {
            using (XmlReader reader = XmlReader.Create(filepath))
            {
                string name;
                bool started = false;
                while (reader.Read())
                {
                    if (reader.MoveToContent() == XmlNodeType.Element)
                    {
                        name = reader.Name.ToLower();
                        if (name == "game")
                        {
                            if (started)
                                throw new Exception("Nodes of type 'game' cannot be nested");
                            started = true;
                            continue;
                        }
                        else if (!started)
                            throw new Exception("A node of type 'game' must be instantiated and all other nodes nested inside it");

                        switch (name)
                        {
                            case "team":
                                teams.Add(reader.GetAttribute("name"), 0);
                                break;
                            case "category":
                                string sort = reader.GetAttribute("sort"), categoryName = reader.GetAttribute("name");
                                bool toSort = false;
                                if (sort != null)
                                    toSort = gInclude.Parse.String2Bool(sort);
                                categories.Add(LoadCategory(reader.GetAttribute("name"), toSort, reader.ReadSubtree()));
                                break;
                            default:
                                throw new Exception("Nodes of type '" + name + "' are not supported.");
                        }
                    }
                }
            }
        }
        private Category LoadCategory(string cName, bool cSort, XmlReader reader)
        {
            using (reader)
            {
                string name;
                Dictionary<Question, int> questions = new Dictionary<Question, int>();
                reader.Read();
                while (reader.Read())
                {
                    if (reader.MoveToContent() == XmlNodeType.Element)
                    {
                        name = reader.Name.ToLower();
                        if (name == "question")
                        {
                            int ptVal;
                            try { ptVal = int.Parse(reader.GetAttribute("points")); } catch { ptVal = 0; }
                            string text = reader.GetAttribute("text");
                            string imagePath = reader.GetAttribute("image");
                            var answers = ReadAnswers(reader.ReadSubtree());
                            questions.Add(new Question(text, imagePath, answers), ptVal);
                            unansweredQ++;
                        }
                        else
                            throw new Exception("Nodes of type '" + name + "' are not supported.");
                    }
                }
                return new Category(cName, cSort, questions);
            }
        }
        private string[] ReadAnswers(XmlReader reader)
        {
            using (reader)
            {
                string name;
                List<string> answers = new List<string>();
                reader.Read();
                while (reader.Read())
                {
                    if (reader.MoveToContent() == XmlNodeType.Element)
                    {
                        name = reader.Name.ToLower();
                        if (name == "answer")
                            answers.Add(reader.ReadString());
                        else
                            throw new Exception("Nodes of type '" + name + "' are not supported.");
                    }
                }
                return answers.ToArray();
            }
        }

        public bool AnswerQuestion(Category category, Question q, string answer)
        {
            if (category == null)
                throw new ArgumentNullException("category");
            if (q == null)
                throw new ArgumentNullException("q");
            if (answer == null)
                throw new ArgumentNullException("answer");

            bool toRet = false;
            if (category.AnswerQuestion(q, answer))
            {
                teams[TeamAt(currentTeam).Key] += category.GetPointValue(q);
                unansweredQ--;
                toRet = true;
            }
            currentTeam++;
            currentTeam = currentTeam % teams.Count;
            return toRet;
        }

        public List<Category> Categories
        {
            get { return categories; }
        }

        public Dictionary<string, int> Teams
        {
            get { return teams; }
        }

        public int CurrentTeamNumber
        {
            get { return currentTeam; }
        }

        public KeyValuePair<string, int> TeamAt(int number)
        {
            int i = -1;
            foreach (var pair in teams)
            {
                i++;
                if (i == number)
                    return pair;
            }
            return new KeyValuePair<string,int>();
        }

        public bool IsGameOver
        {
            get { return unansweredQ == 0; }
        }

        public int DetermineWinningTeam()
        {
            int ID = -1, highscore = 0, winningID = 0;
            foreach (var team in teams)
            {
                ID++;
                if (team.Value > highscore)
                {
                    highscore = team.Value;
                    winningID = ID;
                }
            }
            return winningID;
        }
    }
}
